package com.working.libview.widget.fish

import android.animation.ValueAnimator
import android.graphics.*
import android.graphics.drawable.Drawable
import android.view.animation.LinearInterpolator
import kotlin.math.cos
import kotlin.math.sin


class FishDrawable : Drawable() {
    companion object {
        const val CONSTANT_MIDDLE = 4.19f
    }

    private val mPaint: Paint by lazy {
        Paint().apply {
            isAntiAlias = true
            style = Paint.Style.FILL
            //防抖动，颜色更连贯
            isDither = true
            //设置颜色
            color = Color.argb(OTHER_ALPHA, 244, 92, 71)

        }
    }

    private val mPath: Path by lazy {
        Path()
    }

    private val OTHER_ALPHA = 110
    private val BODY_ALPHA = 160
    var frequence = 1f

    //鱼头半径
    val headRadius = 50f

    //重心
    val middlePoint: PointF by lazy { PointF(4.19f * headRadius, 4.19f * headRadius) }
    lateinit var headPoint: PointF
    var originMainAngle = 90f

    init {
        //设置属性动画  0 -360的是一个周期，设置360的倍数,利用sin实现周期变化
        val valueAnimator = ValueAnimator.ofFloat(0f, 720f)
        valueAnimator.duration = (3 * 1000).toLong()
        valueAnimator.repeatMode = ValueAnimator.REVERSE
        //重复的次数
        valueAnimator.repeatCount = ValueAnimator.INFINITE
        //设置插值器，线性插值器
        valueAnimator.interpolator = LinearInterpolator()
        valueAnimator.addUpdateListener {
            currentValue = it.animatedValue as Float
            invalidateSelf()
        }
        valueAnimator.start()
    }


    //鱼身长度
    private val BODY_LENGTH = headRadius * 3.2f

    //鱼鳍的长度
    private val RIGHT_FINS_LENGTH = headRadius * 1.3f
    private val FIND_FINS_POINT_LENGTH = headRadius * 0.9f

    //节肢圆半径
    private val BIG_CIRCLE_RADIUS = headRadius * 0.7f
    private val MID_CIRCLE_RADIUS = BIG_CIRCLE_RADIUS * 0.6f
    private val SMALL_CIRCLE_RADIUS = MID_CIRCLE_RADIUS * 0.4f

    //寻找圆心的线长
    private val FIND_MID_CIRCLE_LENGTH = BIG_CIRCLE_RADIUS * (1 + 0.6f)
    private val FIND_SMALL_CIRCLE_LENGTH = MID_CIRCLE_RADIUS * (0.4f + 2.7f)
    private val FIND_TRIANGLE_LENGTH = MID_CIRCLE_RADIUS * 2.7f

    private var currentValue = 0f

    override fun getIntrinsicHeight(): Int {
        return (2 * CONSTANT_MIDDLE * headRadius).toInt()
    }

    override fun getIntrinsicWidth(): Int {
        return (2 * CONSTANT_MIDDLE * headRadius).toInt()
    }

    override fun draw(canvas: Canvas) {
        val headAngle =
            (originMainAngle + sin(Math.toRadians(currentValue * 1.2 * frequence)) * 10).toFloat()
        //鱼头圆心坐标
        //鱼头圆心坐标
        headPoint = calculatePoint(middlePoint, BODY_LENGTH / 2, headAngle)
        canvas.drawCircle(headPoint.x, headPoint.y, headRadius, mPaint)

        //右鱼鳍起点

        //右鱼鳍起点
        val finsRightStartPoint =
            calculatePoint(headPoint, FIND_FINS_POINT_LENGTH, headAngle - 110)
        drawRightFins(canvas, finsRightStartPoint, headAngle, true)
        //左鱼鳍起点
        //左鱼鳍起点
        val finsLeftStartPoint =
            calculatePoint(headPoint, FIND_FINS_POINT_LENGTH, headAngle + 110)
        drawRightFins(canvas, finsLeftStartPoint, headAngle, false)

        //节肢1

        //节肢1
        val bodyBottomCenter = calculatePoint(headPoint, BODY_LENGTH, headAngle - 180)
        val triangleTop = drawSegment(
            canvas,
            bodyBottomCenter,
            BIG_CIRCLE_RADIUS,
            MID_CIRCLE_RADIUS,
            FIND_MID_CIRCLE_LENGTH,
            headAngle,
            true
        )

        //节肢2

        //节肢2
        drawSegment(
            canvas,
            triangleTop,
            MID_CIRCLE_RADIUS,
            SMALL_CIRCLE_RADIUS,
            FIND_SMALL_CIRCLE_LENGTH,
            headAngle,
            false
        )

        //此处sin cos一样的

        //此处sin cos一样的
        val findEdgeLength =
            (cos(Math.toRadians(currentValue * 1.5 * frequence)) * BIG_CIRCLE_RADIUS).toFloat()
        //画三角形
        //画三角形
        drawTriangle(canvas, triangleTop, findEdgeLength, FIND_TRIANGLE_LENGTH, headAngle - 180)
        drawTriangle(
            canvas,
            triangleTop,
            findEdgeLength - 20,
            FIND_TRIANGLE_LENGTH - 10,
            headAngle - 180
        )

        //画身体

        //画身体
        drawBody(canvas, headPoint, bodyBottomCenter, headAngle)
    }

    override fun setAlpha(alpha: Int) {
        mPaint.alpha = alpha
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {
        mPaint.colorFilter = colorFilter
    }


    override fun getOpacity(): Int {
        return PixelFormat.TRANSLUCENT
    }

    private fun drawBody(
        canvas: Canvas,
        headPoint: PointF,
        bodyBottomCenter: PointF,
        headAngle: Float
    ) {
        val headPointRight = calculatePoint(headPoint, headRadius, headAngle - 90)
        val headPointLeft = calculatePoint(headPoint, headRadius, headAngle + 90)
        val bodyBottomRight = calculatePoint(bodyBottomCenter, BIG_CIRCLE_RADIUS, headAngle - 90)
        val bodyBottomLeft = calculatePoint(bodyBottomCenter, BIG_CIRCLE_RADIUS, headAngle + 90)

        //计算控制点 决定鱼的胖瘦
        val rightControlPoint = calculatePoint(headPoint, BODY_LENGTH * 0.56f, headAngle - 130)
        val leftControlPoint = calculatePoint(headPoint, BODY_LENGTH * 0.56f, headAngle + 130)
        mPath.reset()
        mPath.moveTo(headPointRight.x, headPointRight.y)
        mPath.quadTo(rightControlPoint.x, rightControlPoint.y, bodyBottomRight.x, bodyBottomRight.y)
        mPath.lineTo(bodyBottomLeft.x, bodyBottomLeft.y)
        mPath.quadTo(leftControlPoint.x, leftControlPoint.y, headPointLeft.x, headPointLeft.y)
        mPaint.alpha = BODY_ALPHA
        canvas.drawPath(mPath, mPaint)
    }

    private fun drawTriangle(
        canvas: Canvas,
        startPoint: PointF,
        triangleRadius: Float,
        length: Float,
        headAngle: Float
    ) {
        val segmentAngle =
            (headAngle + sin(Math.toRadians(currentValue * 1.5 * frequence)) * 35).toFloat()
        //三角形底边中心
        val triangleCenter = calculatePoint(startPoint, length, segmentAngle)
        val triangleRight = calculatePoint(triangleCenter, triangleRadius, segmentAngle - 90)
        val triangleLeft = calculatePoint(triangleCenter, triangleRadius, segmentAngle + 90)

        //画三角形
        mPath.reset()
        mPath.moveTo(startPoint.x, startPoint.y)
        mPath.lineTo(triangleRight.x, triangleRight.y)
        mPath.lineTo(triangleLeft.x, triangleLeft.y)
        canvas.drawPath(mPath, mPaint)
    }

    private fun drawSegment(
        canvas: Canvas,
        trapezoidBottomCenter: PointF,
        bigRadius: Float,
        smallRadius: Float,
        findLength: Float,
        headAngle: Float,
        hasCircle: Boolean
    ): PointF {
        val segmentAngle: Float = if (hasCircle) {
            //节肢1
            //乘以2是改变频率
            (headAngle + cos(Math.toRadians(currentValue * 1.5 * frequence)) * 15).toFloat()
        } else {
            //节肢1
            (headAngle + sin(Math.toRadians(currentValue * 1.5 * frequence)) * 35).toFloat()
        }
        val trapezoidUpperCenter =
            calculatePoint(trapezoidBottomCenter, findLength, segmentAngle - 180)
        //梯形4个点
        val trapezoidBottomRight =
            calculatePoint(trapezoidBottomCenter, bigRadius, segmentAngle - 90)
        val trapezoidBottomLeft =
            calculatePoint(trapezoidBottomCenter, bigRadius, segmentAngle + 90)
        val trapezoidUpperRight =
            calculatePoint(trapezoidUpperCenter, smallRadius, segmentAngle - 90)
        val trapezoidUpperLeft =
            calculatePoint(trapezoidUpperCenter, smallRadius, segmentAngle + 90)

        //画圆
        if (hasCircle) {
            canvas.drawCircle(trapezoidBottomCenter.x, trapezoidBottomCenter.y, bigRadius, mPaint)
        }
        canvas.drawCircle(trapezoidUpperCenter.x, trapezoidUpperCenter.y, smallRadius, mPaint)

        //画梯形
        mPath.reset()
        mPath.moveTo(trapezoidBottomLeft.x, trapezoidBottomLeft.y)
        mPath.lineTo(trapezoidBottomRight.x, trapezoidBottomRight.y)
        mPath.lineTo(trapezoidUpperRight.x, trapezoidUpperRight.y)
        mPath.lineTo(trapezoidUpperLeft.x, trapezoidUpperLeft.y)
        canvas.drawPath(mPath, mPaint)
        return trapezoidUpperCenter
    }

    private fun drawRightFins(
        canvas: Canvas,
        finsStartPoint: PointF,
        headAngle: Float,
        isRight: Boolean
    ) {
        //贝塞尔曲线控制角度，可以自己试
        val controlAngle = 115f
        //减去180的原因是点在开始点左边
        val changLength = sin(Math.toRadians(currentValue * 1.5 * frequence))
            .toFloat() * 50f + RIGHT_FINS_LENGTH * 1.5f
        val finsEndPoint = calculatePoint(finsStartPoint, RIGHT_FINS_LENGTH, headAngle - 180)
        val controlPoint = calculatePoint(
            finsStartPoint, changLength,
            if (isRight) headAngle - controlAngle else headAngle + controlAngle
        )

        //绘制鱼鳍
        mPath.reset()
        mPath.moveTo(finsStartPoint.x, finsStartPoint.y)
        //二阶贝塞尔曲线方法
        mPath.quadTo(controlPoint.x, controlPoint.y, finsEndPoint.x, finsEndPoint.y)
        canvas.drawPath(mPath, mPaint)
    }

    fun calculatePoint(startPoint: PointF, length: Float, angle: Float): PointF {
        //X坐标计算
        val x = cos(Math.toRadians(angle.toDouble())).toFloat() * length
        //Y坐标计算
        val y = sin(Math.toRadians((angle - 180).toDouble())).toFloat() * length
        return PointF(startPoint.x + x, startPoint.y + y)
    }

}